//
// Created by par on 2022/11/29.
//

// #ifndef AOS_SOCK_HPP
// #define AOS_SOCK_HPP
#pragma once

#include <string>
#include <sys/socket.h>
#include <iostream>
#include <fmt/core.h>
#include <chrono>
#include <thread>
#include <fstream>

#define BUF_SIZE 4096
// 类似日志输出
//#define LOG

using namespace std;

char buf[BUF_SIZE];

struct Code {
    static string OK, ERR;
};
string Code::OK = "ok";
string Code::ERR = "err";

/**
 * 发送简单字符串
 * @param sockfd 发送方
 * @param str 字符串
 */
void sendStr(int sockfd, const string &str) {
    send(sockfd, str.c_str(), str.size(), 0);

#ifdef LOG
    cout << fmt::format("send ==> {}", str) << endl;
#endif
    // 延迟避免缓存
    this_thread::sleep_for(chrono::milliseconds(1));
}


/**
 * 接收简单字符串
 * @param sockfd 从哪接收
 */
string recvStr(int sockfd) {
    bzero(buf, sizeof(buf));
    recv(sockfd, buf, BUF_SIZE, 0);
#ifdef LOG
    cout << fmt::format("recv <== {}", buf) << endl;
#endif
    return buf;
}

/**
 * 发送文件内容
 * @param sockfd 发送方
 * @return 文件是否存在
 */
bool sendFile(int sockfd, const string &filepth) {
    ifstream ifs(filepth);
    if (!ifs.is_open()) {
        sendStr(sockfd, Code::ERR);
        return false;
    }

    sendStr(sockfd, Code::OK);
#ifdef LOG
    cout << fmt::format("send file ==> {}", filepth) << endl;
#endif

    string str_buf;
    while (getline(ifs, str_buf)) {
        send(sockfd, str_buf.c_str(), str_buf.size(), 0);
    }
    ifs.close();
    return true;
}

/**
 * 接收文件内容并保存
 * @param sockfd 从哪接收
 * @param filepth 文件路径
 * @return 能否接收
 */
bool recvFile(int sockfd, const string &filepth) {
    if (recvStr(sockfd) == Code::ERR) {
        cout << fmt::format("fail to download {}", filepth) << endl;
        return false;
    }

#ifdef LOG
    cout << fmt::format("recv file ==> {}", filepth) << endl;
#endif

    cout << fmt::format("start downloading {}...", filepth) << endl;
    ofstream ofs(filepth);
    size_t n;
    while ((n = recv(sockfd, buf, BUF_SIZE, 0)) > 0) {
        ofs.write(buf, n);
    }
    ofs.close();
    cout << fmt::format("Ok {}", filepth) << endl;
    return true;
}

// #endif //AOS_SOCK_HPP
